package com.guli.mall.pms.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.guli.mall.pms.entity.CategoryBrandRelationEntity;
import com.guli.mall.pms.entity.vo.BrandAndCategoryIdVo;
import com.guli.mall.pms.feign.AliOssFeignClient;
import com.guli.mall.pms.feign.ProductCategoryFeignClient;
import com.guli.mall.pms.service.CategoryBrandRelationService;
import com.guli.mall.serviceBase.globalException.MallException;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guli.common.utils.PageUtils;
import com.guli.common.utils.Query;

import com.guli.mall.pms.mapper.BrandMapper;
import com.guli.mall.pms.entity.BrandEntity;
import com.guli.mall.pms.service.BrandService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;


@Service("brandService")
@Slf4j
public class BrandServiceImpl extends ServiceImpl<BrandMapper, BrandEntity> implements BrandService {

    @Resource
    AliOssFeignClient aliOssFeignClient;

    @Resource
    CategoryBrandRelationService categoryBrandRelationService;

    @Resource
    ProductCategoryFeignClient productCategoryFeignClient;

    @Resource
    RedissonClient redissonClient;

    @Resource
    StringRedisTemplate stringRedisTemplate;


    @Override
    public PageUtils<BrandEntity> queryPage(Integer currentPage, Integer size) {

        Page<BrandEntity> page = new Page<>(currentPage, size);

        Page<BrandEntity> resultPage = this.page(page);

        return new PageUtils<>(resultPage);
    }

    @Override
    public void deleteLogoOfDbAndAliOss(Long brandId, String logoUrl) {

        BrandEntity brandEntity = new BrandEntity();

        brandEntity.setBrandId(brandId);

        brandEntity.setLogo("");

        this.updateById(brandEntity);

        aliOssFeignClient.deleteFileByObjectURL(logoUrl);
    }

    @Transactional
    @Override
    public void deleteBatch(List<Long> brandIdList) {
        List<BrandEntity> brandEntities = this.baseMapper.selectBatchIds(brandIdList);

        this.removeByIds(brandIdList);

        for (BrandEntity brandEntity : brandEntities) {
            if (!ObjectUtils.isEmpty(brandEntity.getLogo())) {
                /**
                 * 有logo的话，连着logo一起删除
                 * */
                aliOssFeignClient.deleteFileByObjectURL(brandEntity.getLogo());
            }
            //TODO pms_category_brand_relation 表中的关系数据还没有被删除
        }


    }


    @Transactional
    @Override
    public void updateDetail(BrandEntity brand) {


        /**
         * 如果更新的时候logo字段成为了 "" ，则也要将阿里云Oss上的图片删除
         * 因为有前端校验，所以这里一般不会为 ""，一般不会触发
         * */
        if ("".equals(brand.getLogo())) {

            BrandEntity byId = this.getById(brand.getBrandId());

            log.info("此次更新删除品牌logo" + byId.getLogo());

            aliOssFeignClient.deleteFileByObjectURL(byId.getLogo());
        }

        this.updateById(brand);

        /**
         * 更新category-brand-relation 表中的 brandName 字段
         * */
        if (!StringUtils.isEmpty(brand.getName())) {

            CategoryBrandRelationEntity relationEntity = new CategoryBrandRelationEntity();

            relationEntity.setBrandName(brand.getName());

            //relationEntity.setBrandId(brand.getBrandId());

            QueryWrapper<CategoryBrandRelationEntity> wrapper = new QueryWrapper<>();

            wrapper.eq("brand_id", brand.getBrandId());

            categoryBrandRelationService.update(relationEntity, wrapper);
        }

    }

    @Override
    public PageUtils<BrandEntity> getBrandListPaginationByCategoryId(Integer currentPage, Integer size, Long categoryId) {

        Page<CategoryBrandRelationEntity> brandEntityPage = new Page<>(currentPage, size);

        QueryWrapper<CategoryBrandRelationEntity> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("catelog_id", categoryId);
        /**
         * 先从brand-category-relation表中分页查询到所有与categoryId相同的记录
         * */
        Page<CategoryBrandRelationEntity> page = categoryBrandRelationService.page(brandEntityPage, queryWrapper);

        // 单独取出 brandId 并作为集合
        List<Long> brandIdList = page.getRecords().stream().map(relation -> {
            return relation.getBrandId();
        }).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(brandIdList)) {
            throw new MallException("该分类下没有与之对应的品牌可供选择");
        }

        /**
         * 再根据 brandId 集合查询出brandId
         * */
        List<BrandEntity> brandEntities = this.baseMapper.selectBatchIds(brandIdList);

        /**
         * 复制分页信息
         * */
        Page<BrandEntity> brandPage = new Page<>(currentPage, size);

        brandPage.setRecords(brandEntities);

        brandPage.setTotal(page.getTotal());

        return new PageUtils<>(brandPage);
    }

    @Transactional
    @Override
    public BrandEntity saveBrandAndBrandCategoryRelation(BrandAndCategoryIdVo brandAndCategoryIdVo) {

        String categoryName = productCategoryFeignClient.getCategoryName(brandAndCategoryIdVo.getCategoryId());

        if (StringUtils.isEmpty(categoryName)) {
            throw new MallException("查询不到categoryId = " + brandAndCategoryIdVo.getCategoryId() + "的品牌");
        }

        BrandEntity brandEntity = new BrandEntity();

        BeanUtils.copyProperties(brandAndCategoryIdVo, brandEntity);

        this.save(brandEntity);

        CategoryBrandRelationEntity categoryBrandRelationEntity = new CategoryBrandRelationEntity();

        categoryBrandRelationEntity.setBrandId(brandEntity.getBrandId());

        categoryBrandRelationEntity.setBrandName(brandEntity.getName());

        categoryBrandRelationEntity.setCatelogId(brandAndCategoryIdVo.getCategoryId());

        categoryBrandRelationEntity.setCatelogName(categoryName);

        categoryBrandRelationService.save(categoryBrandRelationEntity);

        return brandEntity;
    }

    @Override
    public List<BrandEntity> getBrandByCondition(BrandAndCategoryIdVo brandAndCategoryIdVo) {

        QueryWrapper<BrandEntity> brandEntityQueryWrapper = null;

        if (!ObjectUtils.isEmpty(brandAndCategoryIdVo)) {
            brandEntityQueryWrapper = new QueryWrapper<>();
            if (!ObjectUtils.isEmpty(brandAndCategoryIdVo.getName())) {
                brandEntityQueryWrapper.like("name", brandAndCategoryIdVo.getName());
            }
            if (!ObjectUtils.isEmpty(brandAndCategoryIdVo.getCategoryId())) {
                //brandEntityQueryWrapper.eq("catelog_id",brandAndCategoryIdVo.getCategoryId());
                QueryWrapper<CategoryBrandRelationEntity> wrapper = new QueryWrapper<>();

                wrapper.eq("catelog_id", brandAndCategoryIdVo.getCategoryId()).select("brand_id");

                List<CategoryBrandRelationEntity> brandList = categoryBrandRelationService.list(wrapper);

                List<Long> brandIdList = brandList.stream().map(brand -> {
                    return brand.getBrandId();
                }).collect(Collectors.toList());

                brandEntityQueryWrapper.in("brand_id", brandIdList);

                if (CollectionUtils.isEmpty(brandIdList)) {

                    log.error("categroyId = {}，没有对应的品牌", brandAndCategoryIdVo.getCategoryId());

                    return null;
                }


            }
            if (!ObjectUtils.isEmpty(brandAndCategoryIdVo.getShowStatus())) {
                brandEntityQueryWrapper.eq("show_status", brandAndCategoryIdVo.getShowStatus());
            }
            if (!ObjectUtils.isEmpty(brandAndCategoryIdVo.getFirstLetter())) {
                brandEntityQueryWrapper.eq("first_letter", brandAndCategoryIdVo.getFirstLetter());
            }
        }

        List<BrandEntity> list = this.list(brandEntityQueryWrapper);

        return list;
    }


    @Override
    public List<BrandEntity> getBrandListByCategoryIdList(List<Long> categoryIdList) {

        List<BrandEntity> brandEntities = new ArrayList<>();

        //BrandService brandService = applicationContext.getBean(BrandService.class);

        for (Long categoryId : categoryIdList) {

            List<BrandEntity> brandListByCategoryId = this.getBrandListByCategoryId(categoryId);

            brandEntities.addAll(brandListByCategoryId);
        }

        return brandEntities;
    }

    private static final String BRAND_CACHE = "categoryId-brandList";

    private static final String BRAND_READ_WRITE_LOCK = "brand-read-write-lock";

    private static final TypeReference<List<BrandEntity>> BRAND_ENTITY_LIST_TYPE_REFERENCE = new TypeReference<List<BrandEntity>>() {
    };

    //@Cacheable(cacheNames = "tempCache", key = "#a0")
    @Override
    public List<BrandEntity> getBrandListByCategoryId(Long categoryId) {

        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();

        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(BRAND_READ_WRITE_LOCK);

        RLock rLock = readWriteLock.readLock();

        rLock.lock();

        try {

            String s = ops.get(BRAND_CACHE + "::" + categoryId.toString());

            List<BrandEntity> brandEntities = JSON.parseObject(s, BRAND_ENTITY_LIST_TYPE_REFERENCE);

            if (!CollectionUtils.isEmpty(brandEntities)) {
                return brandEntities;
            }

        } finally {
            rLock.unlock();
        }

        RLock writeLock = readWriteLock.writeLock();

        writeLock.lock();

        try {
            // 获得锁之后再次判断
            String s = ops.get(BRAND_CACHE + "::" + categoryId.toString());

            List<BrandEntity> brandEntities = JSON.parseObject(s, BRAND_ENTITY_LIST_TYPE_REFERENCE);


            if (!CollectionUtils.isEmpty(brandEntities)) {
                return brandEntities;
            }

            String hostAddr = aliOssFeignClient.getOssHost().get("host").toString() + "/";

            List<CategoryBrandRelationEntity> relation = categoryBrandRelationService.getCategoryBrandRelationListByCategoryId(categoryId);

            List<Long> brandIdList = relation.stream().map(CategoryBrandRelationEntity::getBrandId).collect(Collectors.toList());

            List<BrandEntity> brandEntityList = this.getBaseMapper().selectBatchIds(brandIdList).stream().map(brand -> {
                brand.setLogo(hostAddr + brand.getLogo());
                return brand;
            }).collect(Collectors.toList());

            ops.set(BRAND_CACHE + "::" + categoryId.toString(), JSON.toJSONString(brandEntityList),10, TimeUnit.MINUTES);


            return brandEntityList;

        } finally {
            writeLock.unlock();
        }


    }

}